using System;
using System.Collections.Generic;

namespace OracleInternal.SqlAndPlsqlParser
{
	internal class EarleyParserGrammarDefinition : ParserGrammarDefinition
	{
		public List<int> m_vTopLevelSymbols;

		public HashSet<int>[] m_vHasPathToFirstSymbolTable;

		public List<int>[] m_vHeadToRulesTable;

		public Dictionary<long, FlexibleSizeLongArray> m_vPredictionsTable;

		public virtual OracleMbEarleyRulesPriorityDescriptor[] RulesPriorityDescriptors => null;

		public EarleyParserGrammarDefinition(Set<RuleTuple> rules)
			: base(rules)
		{
			PrioritizeRules();
			BuildHasPathToFirstSymbolTable();
			BuildPredictionsTable();
		}

		protected void PrioritizeRules()
		{
			Map<int, List<int>> map = new Map<int, List<int>>();
			for (int i = 0; i < m_vRules.Length; i++)
			{
				int vHead = m_vRules[i].m_vHead;
				if (!map.TryGetValue(vHead, out var value))
				{
					value = (map[vHead] = new List<int>());
				}
				value.Add(i);
			}
			PrioritizeRules(map);
		}

		protected void PrioritizeRules(Map<int, List<int>> headToRules)
		{
			OracleMbEarleyRulesPriorityDescriptor[] rulesPriorityDescriptors = RulesPriorityDescriptors;
			if (rulesPriorityDescriptors == null)
			{
				return;
			}
			OracleMbEarleyRulesPriorityDescriptor[] array = rulesPriorityDescriptors;
			for (int i = 0; i < array.Length; i++)
			{
				OracleMbEarleyRulesPriorityDescriptor oracleMbEarleyRulesPriorityDescriptor = array[i];
				if (headToRules.TryGetValue(m_vSymbolIndexes[oracleMbEarleyRulesPriorityDescriptor.m_vHeadSymbol], out var value) && oracleMbEarleyRulesPriorityDescriptor.m_vFirstRHSSymbols != null && oracleMbEarleyRulesPriorityDescriptor.m_vFirstRHSSymbols.Length != 0)
				{
					int num = 0;
					int[] array2 = new int[oracleMbEarleyRulesPriorityDescriptor.m_vFirstRHSSymbols.Length];
					string[] vFirstRHSSymbols = oracleMbEarleyRulesPriorityDescriptor.m_vFirstRHSSymbols;
					foreach (string key in vFirstRHSSymbols)
					{
						array2[num++] = m_vSymbolIndexes[key];
					}
					int[] rules = value.ToArray();
					SortRulesOnPriority(rules, array2);
				}
			}
		}

		protected void SortRulesOnPriority(int[] rules, int[] firstRHSSymbolsPriority)
		{
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			int num = firstRHSSymbolsPriority.Length;
			foreach (int num2 in rules)
			{
				ParserRuleTuple parserRuleTuple = m_vRules[num2];
				for (int j = 0; j < num; j++)
				{
					if (parserRuleTuple.m_vRhs[0] == firstRHSSymbolsPriority[j])
					{
						list.Add(j);
						list2.Add(num2);
						break;
					}
				}
			}
			int count = list2.Count;
			ParserRuleTuple[] array = new ParserRuleTuple[count];
			int[] array2 = list2.ToArray();
			Array.Sort(list.ToArray(), array2);
			for (int k = 0; k < count; k++)
			{
				array[k] = m_vRules[array2[k]];
			}
			int num3 = 0;
			foreach (int item in list2)
			{
				m_vRules[item] = array[num3];
				m_vSortedRulesIndexes[array2[num3]] = item;
				num3++;
			}
		}

		protected void BuildHasPathToFirstSymbolTable()
		{
			int num = m_vAllSymbols.Length;
			m_vTopLevelSymbols = new List<int>();
			m_vHasPathToFirstSymbolTable = new HashSet<int>[num];
			m_vHeadToRulesTable = new List<int>[num];
			for (int i = 0; i < m_vRules.Length; i++)
			{
				int vHead = m_vRules[i].m_vHead;
				List<int> list = m_vHeadToRulesTable[vHead];
				if (list == null)
				{
					list = new List<int>(1);
					m_vHeadToRulesTable[vHead] = list;
				}
				list.Add(i);
			}
			for (int j = 0; j < num; j++)
			{
				if ((m_vSymbolsFlags[j] & 6) == 2)
				{
					m_vTopLevelSymbols.Add(j);
				}
			}
			int num2 = m_vAllSymbols.Length;
			bool[] visited = new bool[num2];
			bool[] visiting = new bool[num2];
			bool[] array = new bool[num2];
			for (int k = 0; k < num2; k++)
			{
				BuildHasPathToFirstSymbolTable(k, visited, visiting, array);
			}
			long num3 = 0L;
			long num4 = 0L;
			while (true)
			{
				HashSet<int>[] vHasPathToFirstSymbolTable = m_vHasPathToFirstSymbolTable;
				foreach (HashSet<int> hashSet in vHasPathToFirstSymbolTable)
				{
					num4 += hashSet.Count;
				}
				if (num4 == num3)
				{
					break;
				}
				num3 = num4;
				num4 = 0L;
				for (int m = 0; m < num2; m++)
				{
					if (!array[m])
					{
						CompleteBuildHasPathToFirstSymbolTable(m, array);
					}
				}
			}
		}

		protected void BuildHasPathToFirstSymbolTable(int symbol, bool[] visited, bool[] visiting, bool[] completed)
		{
			visiting[symbol] = true;
			HashSet<int> hashSet;
			if (IsTerminal(symbol))
			{
				hashSet = new HashSet<int>();
				hashSet.Add(symbol);
				m_vHasPathToFirstSymbolTable[symbol] = hashSet;
				visiting[symbol] = false;
				visited[symbol] = true;
				completed[symbol] = true;
				return;
			}
			HashSet<int> hashSet2 = new HashSet<int>();
			bool flag = false;
			hashSet = m_vHasPathToFirstSymbolTable[symbol];
			if (hashSet == null)
			{
				hashSet = new HashSet<int>();
				m_vHasPathToFirstSymbolTable[symbol] = hashSet;
			}
			foreach (int item in m_vHeadToRulesTable[symbol])
			{
				int num = m_vRules[item].m_vRhs[0];
				if (symbol == num || hashSet2.Contains(num))
				{
					continue;
				}
				HashSet<int> other;
				if (visited[num])
				{
					other = m_vHasPathToFirstSymbolTable[num];
				}
				else
				{
					if (visiting[num])
					{
						flag = true;
						hashSet2.Add(num);
						continue;
					}
					BuildHasPathToFirstSymbolTable(num, visited, visiting, completed);
					other = m_vHasPathToFirstSymbolTable[num];
				}
				if (!completed[num])
				{
					flag = true;
				}
				hashSet.UnionWith(other);
				hashSet2.Add(num);
			}
			visiting[symbol] = false;
			visited[symbol] = true;
			if (!flag)
			{
				completed[symbol] = true;
			}
		}

		protected void CompleteBuildHasPathToFirstSymbolTable(int symbol, bool[] completed)
		{
			HashSet<int> hashSet = new HashSet<int>();
			HashSet<int> hashSet2 = m_vHasPathToFirstSymbolTable[symbol];
			if (hashSet2 == null)
			{
				hashSet2 = new HashSet<int>();
				m_vHasPathToFirstSymbolTable[symbol] = hashSet2;
			}
			foreach (int item in m_vHeadToRulesTable[symbol])
			{
				int num = m_vRules[item].m_vRhs[0];
				if (symbol != num && !completed[num] && !hashSet.Contains(num))
				{
					HashSet<int> other = m_vHasPathToFirstSymbolTable[num];
					hashSet2.UnionWith(other);
					hashSet.Add(num);
				}
			}
		}

		protected bool NonTerminalHasPathToTerminal(int nonTerminal, int terminal)
		{
			return m_vHasPathToFirstSymbolTable[nonTerminal].Contains(terminal);
		}

		protected void BuildPredictionsTable()
		{
			m_vPredictionsTable = new Dictionary<long, FlexibleSizeLongArray>();
			int num = m_vAllSymbols.Length;
			bool[] array = new bool[num];
			bool[] visiting = new bool[num];
			bool[] array2 = new bool[num];
			for (int i = 0; i < num; i++)
			{
				if (IsTerminal(i))
				{
					array[i] = true;
					array2[i] = true;
				}
				else
				{
					BuildPredictionsTable(i, array, visiting, array2);
				}
			}
			long num2 = 0L;
			long num3 = 0L;
			while (true)
			{
				foreach (KeyValuePair<long, FlexibleSizeLongArray> item in m_vPredictionsTable)
				{
					num3 += item.Value.m_vContentSize;
				}
				if (num3 == num2)
				{
					break;
				}
				num2 = num3;
				num3 = 0L;
				for (int j = 0; j < num; j++)
				{
					if (!array2[j])
					{
						CompleteBuildPredictionsTable(j, array2);
					}
				}
			}
		}

		protected void BuildPredictionsTable(int symbol, bool[] visited, bool[] visiting, bool[] completed)
		{
			HashSet<int> obj = m_vHasPathToFirstSymbolTable[symbol];
			long num = (long)symbol << 32;
			bool flag = false;
			HashSet<int> hashSet = new HashSet<int>();
			visiting[symbol] = true;
			foreach (int item in obj)
			{
				long key = num | (uint)item;
				m_vPredictionsTable.TryGetValue(key, out var value);
				hashSet.Clear();
				foreach (int item2 in m_vHeadToRulesTable[symbol])
				{
					int[] vRhs = m_vRules[item2].m_vRhs;
					_ = vRhs.Length;
					int num2 = vRhs[0];
					if (IsTerminal(num2))
					{
						if (num2 == item)
						{
							value = FlexibleSizeLongArray.Insert(value, MakeMatrixCellElem(item2, 0));
						}
					}
					else if (symbol == num2)
					{
						value = FlexibleSizeLongArray.Insert(value, MakeMatrixCellElem(item2, 0));
					}
					else
					{
						if (!NonTerminalHasPathToTerminal(num2, item))
						{
							continue;
						}
						if (!hashSet.Contains(num2))
						{
							hashSet.Add(num2);
							if (visiting[num2])
							{
								flag = true;
								value = FlexibleSizeLongArray.Insert(value, MakeMatrixCellElem(item2, 0));
								continue;
							}
							if (!visited[num2])
							{
								BuildPredictionsTable(num2, visited, visiting, completed);
							}
							if (!completed[num2])
							{
								flag = true;
							}
							long key2 = ((long)num2 << 32) | (uint)item;
							if (m_vPredictionsTable.TryGetValue(key2, out var value2))
							{
								value = FlexibleSizeLongArray.Merge(value, value2);
							}
						}
						value = FlexibleSizeLongArray.Insert(value, MakeMatrixCellElem(item2, 0));
					}
				}
				m_vPredictionsTable[key] = value;
			}
			visiting[symbol] = false;
			visited[symbol] = true;
			if (!flag)
			{
				completed[symbol] = true;
			}
		}

		protected void CompleteBuildPredictionsTable(int symbol, bool[] completed)
		{
			HashSet<int> obj = m_vHasPathToFirstSymbolTable[symbol];
			long num = (long)symbol << 32;
			HashSet<int> hashSet = new HashSet<int>();
			foreach (int item in obj)
			{
				long key = num | (uint)item;
				m_vPredictionsTable.TryGetValue(key, out var value);
				hashSet.Clear();
				foreach (int item2 in m_vHeadToRulesTable[symbol])
				{
					int[] vRhs = m_vRules[item2].m_vRhs;
					_ = vRhs.Length;
					int num2 = vRhs[0];
					if (symbol == num2 || completed[num2] || hashSet.Contains(num2))
					{
						continue;
					}
					hashSet.Add(num2);
					if (NonTerminalHasPathToTerminal(num2, item))
					{
						long key2 = ((long)num2 << 32) | (uint)item;
						if (m_vPredictionsTable.TryGetValue(key2, out var value2))
						{
							value = FlexibleSizeLongArray.Merge(value, value2);
						}
					}
				}
				m_vPredictionsTable[key] = value;
			}
		}

		public long MakeMatrixCellElem(int ruleIdx, int position)
		{
			long num = -1L;
			int[] vRhs = m_vRules[ruleIdx].m_vRhs;
			if (position < vRhs.Length)
			{
				num = vRhs[position];
			}
			return ((long)ruleIdx << 12) | (uint)position | (num << 32);
		}

		public virtual void GetTokensInfo(LexerToken token, out int symbolIndex, out bool symbolCouldBeIdentifier)
		{
			symbolCouldBeIdentifier = false;
			switch (token.m_vType)
			{
			case Token.IDENTIFIER:
				symbolIndex = m_vQuotedSymbolIndexes[token.m_vContent];
				if (symbolIndex < 0 || (m_vSymbolsFlags[symbolIndex] & 0x20) == 0)
				{
					symbolCouldBeIdentifier = true;
				}
				break;
			case Token.OPERATION:
				symbolIndex = m_vQuotedSymbolIndexes[token.m_vContent];
				break;
			default:
				symbolIndex = -1;
				break;
			}
		}

		public virtual bool LookaheadOK(int lookAheadSymbol, int symbolIndex, bool symbolCouldBeIdentifier)
		{
			if (lookAheadSymbol < 0 || symbolIndex < 0)
			{
				return true;
			}
			if (!IsTerminal(lookAheadSymbol))
			{
				return CanBePrediction(lookAheadSymbol, symbolIndex, symbolCouldBeIdentifier);
			}
			return lookAheadSymbol == symbolIndex;
		}

		public virtual bool CanBePrediction(int symbol, int firstSymbol, bool firstSymbolCouldBeIdentifier)
		{
			return m_vHasPathToFirstSymbolTable[symbol].Contains(firstSymbol);
		}

		public int GetNextSymbol(long state)
		{
			int num = (int)state;
			int[] vRhs = m_vRules[num >> 12].m_vRhs;
			num &= 0xFFF;
			if (num >= vRhs.Length)
			{
				return -1;
			}
			return vRhs[num];
		}

		public int GetRuleHead(long state)
		{
			int num = (int)state >> 12;
			return m_vRules[num].m_vHead;
		}
	}
}
